package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>
        implements ISysMenuService {

    @Override
    public List<RouterVo> buildMenus(Long userId) {
        List<SysMenu> menus = list();

        List<SysMenu> menuTree = getChildPerms(menus, 0);

        return menu2Router(menuTree);
    }

    @Override
    public List<TreeSelect> buildMenuTreeSelect(Long roleId) {
        List<SysMenu> menus = list();
        List<SysMenu> menuTrees = buildMenuTree(menus);
        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    private List<SysMenu> buildMenuTree(List<SysMenu> menus) {
        // 1. 预构建父节点到子节点的映射（提升查找效率）
        Map<Long, List<SysMenu>> parentIdToChildrenMap = menus.stream()
                .collect(Collectors.groupingBy(SysMenu::getParentId));

        // 2. 直接获取父节点的子节点列表，并递归构建树
        List<SysMenu> returnList = new ArrayList<>();
        for (SysMenu menu : menus) {
            if (isRoot(menu)) {
                buildTree(parentIdToChildrenMap, menu);
                returnList.add(menu);
            }
        }

        if (returnList.isEmpty()) {
            returnList = menus;
        }
        return returnList;
    }

    private List<RouterVo> menu2Router(List<SysMenu> menus) {
        List<RouterVo> routers = new LinkedList<>();
        for (SysMenu menu : menus) {
            RouterVo router = buildBaseRouter(menu);
            handleChildrenRoutes(menu, router);
            routers.add(router);
        }
        return routers;
    }

    /**
     * 根据父ID获取所有子菜单（递归构建树形结构）
     *
     * @param list     菜单列表（平铺结构）
     * @param parentId 目标父菜单ID（需与菜单ID类型一致，此处假设为long）
     * @return 树形结构子菜单列表
     */
    private List<SysMenu> getChildPerms(List<SysMenu> list, long parentId) {
        // 1. 预构建父节点到子节点的映射（提升查找效率）
        Map<Long, List<SysMenu>> parentIdToChildrenMap = list.stream()
                .collect(Collectors.groupingBy(SysMenu::getParentId));

        // 2. 直接获取父节点的子节点列表，并递归构建树
        List<SysMenu> returnList = new ArrayList<>();
        for (SysMenu menu : list) {
            if (menu.getParentId() == parentId) {
                buildTree(parentIdToChildrenMap, menu);
                returnList.add(menu);
            }
        }
        return returnList;
    }

    /**
     * 递归构建菜单树形结构（基于预生成的映射）
     *
     * @param parentMap   父节点到子节点的映射
     * @param currentNode 当前处理节点
     */
    private void buildTree(Map<Long, List<SysMenu>> parentMap, SysMenu currentNode) {
        List<SysMenu> childList = parentMap.getOrDefault(currentNode.getMenuId(), new ArrayList<>());
        currentNode.setChildren(childList);
        for (SysMenu child : childList) {
            buildTree(parentMap, child); // 递归处理子节点
        }
    }

    /**
     * 构建基础路由信息
     */
    private RouterVo buildBaseRouter(SysMenu menu) {
        RouterVo router = new RouterVo();
        router.setHidden("1".equals(menu.getVisible()));

        router.setName(getRouteName(menu));
        router.setPath(getRouterPath(menu));
        router.setComponent(getComponent(menu));

        router.setQuery(menu.getQuery());
        router.setMeta(buildMetaData(menu));
        return router;
    }

    /**
     * 处理子路由的特殊情况
     */
    private void handleChildrenRoutes(SysMenu menu, RouterVo router) {
        List<SysMenu> childMenus = menu.getChildren();

        // 处理目录类型
        if (isDirectoryWithChildren(menu, childMenus)) {
            router.setAlwaysShow(true);
            router.setRedirect("noRedirect");
            router.setChildren(menu2Router(childMenus));
            return;
        }

        // 处理根菜单
        if (isRootMenu(menu)) {
            handleRootMenu(menu, router);
            return;
        }

        // 处理根菜单的内部链接
        if (isRootInnerLink(menu)) {
            handleRootInnerLink(menu, router);
        }
    }

    /**
     * 构建元数据信息
     */
    private MetaVo buildMetaData(SysMenu menu) {
        return new MetaVo(
                menu.getMenuName(),
                menu.getIcon(),
                "1".equals(menu.getIsCache()),
                menu.getPath()
        );
    }

    /**
     * 处理菜单框架的特殊情况
     */
    private void handleRootMenu(SysMenu menu, RouterVo router) {
        router.setMeta(null);
        RouterVo child = buildBaseRouter(menu);
        child.setPath(menu.getPath()); // 覆盖路径
        child.setComponent(menu.getComponent());
        child.setName(getRouteName(menu.getRouteName(), menu.getPath()));
        router.setChildren(Collections.singletonList(child));
    }

    /**
     * 处理内部链接的特殊情况
     */
    private void handleRootInnerLink(SysMenu menu, RouterVo router) {
        router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
        router.setPath("/");

        RouterVo child = new RouterVo();
        child.setPath(innerLinkReplaceEach(menu.getPath()));
        child.setComponent(UserConstants.INNER_LINK);
        child.setName(getRouteName(menu.getRouteName(), child.getPath()));
        child.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));

        router.setChildren(Collections.singletonList(child));
    }

    /* 以下为辅助方法 */

    /**
     * 判断是否为目录类型且包含子菜单
     */
    private boolean isDirectoryWithChildren(SysMenu menu, List<SysMenu> childMenus) {
        return CollectionUtils.isNotEmpty(childMenus)
                && UserConstants.TYPE_DIR.equals(menu.getMenuType());
    }

    /**
     * 判断是否为根菜单
     */
    private boolean isRootMenu(SysMenu menu) {
        return isRoot(menu)
                && UserConstants.TYPE_MENU.equals(menu.getMenuType())
                && UserConstants.NO_FRAME.equals(menu.getIsFrame());
    }

    /**
     * 判断是否为根内部链接
     */
    private boolean isRootInnerLink(SysMenu menu) {
        return isRoot(menu) && isInnerLink(menu);
    }

    /**
     * 判断是否内部展示的地址
     */
    private boolean isInnerLink(SysMenu menu) {
        return UserConstants.NO_FRAME.equals(menu.getIsFrame())
                && StringUtils.ishttp(menu.getPath());
    }

    /**
     * 判断是否为根菜单（parentId为0）
     */
    private boolean isRoot(SysMenu menu) {
        return menu.getParentId() != null && menu.getParentId().intValue() == 0;
    }

    /**
     * 获取路由名称（优先使用配置的路由名）
     */
    private String getRouteName(SysMenu menu) {
        return isRootMenu(menu)
                ? StringUtils.EMPTY
                : getRouteName(menu.getRouteName(), menu.getPath());
    }

    /**
     * 生成最终路由名称（首字母大写）
     */
    private String getRouteName(String routeName, String path) {
        return StringUtils.capitalize(StringUtils.defaultIfEmpty(routeName, path));
    }

    /**
     * 获取路由路径（处理特殊路径情况）
     */
    private String getRouterPath(SysMenu menu) {
        if (isNonRootInnerLink(menu)) {
            return innerLinkReplaceEach(menu.getPath());
        }

        if (isRootDirectoryFrame(menu)) {
            return "/" + menu.getPath();
        }

        return isRootMenu(menu) ? "/" : menu.getPath();
    }

    /**
     * 判断非根菜单的内部链接
     */
    private boolean isNonRootInnerLink(SysMenu menu) {
        return !isRoot(menu) && isInnerLink(menu);
    }

    /**
     * 判断是否为根目录框架
     */
    private boolean isRootDirectoryFrame(SysMenu menu) {
        return isRoot(menu)
                && UserConstants.TYPE_DIR.equals(menu.getMenuType())
                && UserConstants.NO_FRAME.equals(menu.getIsFrame());
    }

    /**
     * 获取组件路径（智能处理不同情况）
     */
    private String getComponent(SysMenu menu) {
        if (StringUtils.isNotEmpty(menu.getComponent()) && !isRootMenu(menu)) {
            return menu.getComponent();
        }
        if (isInnerLinkComponent(menu)) {
            return UserConstants.INNER_LINK;
        }
        if (isParentView(menu)) {
            return UserConstants.PARENT_VIEW;
        }
        return UserConstants.LAYOUT;
    }

    private boolean isInnerLinkComponent(SysMenu menu) {
        return StringUtils.isEmpty(menu.getComponent())
                && menu.getParentId().intValue() != 0
                && isInnerLink(menu);
    }

    /**
     * 判断是否需要父视图组件
     */
    private boolean isParentView(SysMenu menu) {
        return !isRoot(menu) && UserConstants.TYPE_DIR.equals(menu.getMenuType());
    }

    /**
     * 处理内部链接路径格式转换（使用正则表达式优化）
     */
    private String innerLinkReplaceEach(String path) {
        return path.replaceAll("^(http|https|www)([.:])+", "")
                .replaceAll("[.:]", "/");
    }
}
